/* 
 * File:   SDSParser.h
 * Author: gip
 *
 * Created on August 7, 2010, 3:19 AM
 */

#ifndef _SDSPARSER_H
#define	_SDSPARSER_H
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <stdlib.h>
#include "SDSFile.h"
#include "MAPFile.h"
#include "PDSFile.h"
#include <process.h>
using namespace std;

class SDSParser {
public:
    SDSParser();
    SDSParser(const SDSParser& orig);
    virtual ~SDSParser();
    bool parseSDS(PDSFile PDS, string current);
private:
    string current_parser;
    int current_entry;
    SDSFile currentSDS;
    PDSFile currentPDS;
    //Sets the current parser and MAP file in PDS file.
    bool setParser(string c);
    //Create SDS object from file
    bool readSDS(SDSFile);
    //Iterates through and parses all data sheet entries
    bool parseDS();
    //Parse single entry
    bool parseDS(string str);
    //Run this before using the parse script file
    bool runBeforeScript();
    //Creates input file using a DS entry
    void createInputFile(string x);
    //Runs the parse script file
    void runParseScript(string x);

    //Reads parser generated output file
    void readOutputFile();
    //Searches for storage rule in MAP file and constructs the
    DMLStatement getSQL();
    //Gets parser related paths
    string getPath();
    string getParserPath();
    void setInputPath();
    string input_path;
    void setOutputPath();
    string output_path;
    string parser_script;
};

SDSParser::SDSParser() {
    current_entry = 0;
}

SDSParser::SDSParser(const SDSParser& orig) {
}

SDSParser::~SDSParser() {
}

bool SDSParser::parseSDS(PDSFile PDS, string current) {
    currentPDS = PDS;
    if (this->setParser(current) == false) {
        return false;
    }
    //
    if (this->readSDS(PDS.getSDS()) == false) {
        return false;
    }
    cout << "SDS FOUND!" << endl;
    if (this->parseDS() == false) {
        return false;
    }

    //SDS parsing was successfuul
    return true;
}

bool SDSParser::setParser(string x) {

    current_parser = x;
    return true;
}

bool SDSParser::readSDS(SDSFile SDS) {
    cout << "Reading SDS from: " << SDS.getPath() << "a" << endl;

    ifstream openSDS(SDS.getPath().c_str());
    if (openSDS.is_open()) {
        currentSDS = SDS;
        currentPDS.setSDS(currentSDS);
        cout << "OK" << SDS.getFilename() << endl;
        return true;
    } else {
        cerr << "ERROR (Parser): No such SDS file" << endl;
        return false;
    }
}

bool SDSParser::parseDS() {
    //Make Parse script executable
    //If file does not exist return false
    if (this->runBeforeScript() == false) {
        cerr << "ERROR (PARSER): Parse Script file missing in /UniApo/Parser";
        cerr << endl;
        return false;
    }
    //TODO: Check if everything is there
    //First get DS component
    int comp = currentSDS.getDScomponent();
    cout << "Data string component is: " << comp << endl;
    //We get the paths and create the parsing instructions to be used later
    //TODO: bool check if empty vector

    //Now we iterate over the DS component of the SDS file
    vector<DynamicDataEntry>::iterator DDEit;
    for (DDEit = currentSDS.getContent().begin();
            DDEit != currentSDS.getContent().end();
            DDEit++) {
        current_entry = current_entry + 1;
        string DS;
        DS = (*DDEit).getContent(comp);
        cout << "***********************************************************";
        cout << "*********************" << endl;
        cout << "PARSING: " << DS << endl;
        cout << "***********************************************************";
        cout << "*********************" << endl;
        this->parseDS(DS);
        currentPDS.buildFile();
    }
}

bool SDSParser::parseDS(string DS) {
    //Declaring individual Data String.


    //Prepare inputfile
    this->createInputFile(DS);

    //Parse Statement
    //Assuming UniApo is build in /Parser/ParserName/
    this->runParseScript(DS);
    this->readOutputFile();

}

bool SDSParser::runBeforeScript() {
    //TODO: Check if script exists or give error
    Dv::Util::Process chmod1("chmod +x parse && chmod 777 parse");
    chmod1.start();
    chmod1.wait();
    //cout << parse.signaled() << endl;
    if (chmod1.signaled() >= 0) {
        this->runBeforeScript();
    }

    stringstream buildparser;
    buildparser << "./parse " << current_parser;
    parser_script = buildparser.str().c_str();
    this->setOutputPath();
    this->setInputPath();
    //cout << "parser script :" << parser_script << endl;;

    return true;

}

void SDSParser::createInputFile(string DS) {
    //cout << "Creating input file:" << input_path << endl;
    ofstream input;
    input.open(input_path.c_str());
    input << DS;
    input.close();
}

void SDSParser::runParseScript(string DS) {
    Dv::Util::Process parse(parser_script.c_str());
    parse.start();
    parse.wait();
    if (parse.signaled() >= 0) {
        
        this->parseDS(DS);
        cout << "some random error occurred, retrying..." << endl;
    }
    //system(parser_script.c_str());
}

void SDSParser::readOutputFile() {
    ifstream output(output_path.c_str());
    ParsedDataString PDS;
    //TO-DO: make nice names

    string line;
    if (output.is_open()) {
        while (!output.eof()) {

            getline(output, line);
            if (line != "") {
                PDS.addContent(line);
            }
        }
    }
    output.close();
    //currentPDS.(currentSDS.getDataString(current_entry));
    currentPDS.addEntry(PDS, current_entry);

}

string SDSParser::getPath() {
    char *p = NULL;
    p = getcwd(NULL, 0); // Get full absolute MAPpath
    string p2 = p;
    string::size_type loc3 = p2.find("/UniApo/", 0);
    return p2.substr(0, loc3 + 8);

}

string SDSParser::getParserPath() {
    stringstream ss;
    ss << this->getPath() << "Parser/" << current_parser << "/";
    return ss.str();

}

void SDSParser::setInputPath() {
    stringstream ss;
    ss << this->getParserPath() << "input";

    input_path = ss.str();
    //cout << "SETTING INPUT PATH: " << input_path << endl;
}

void SDSParser::setOutputPath() {
    stringstream ss;

    ss << this->getParserPath() << "result";
    output_path = ss.str();
    //cout << "SETTING OUTPUT PATH: " << output_path << endl;
}
#endif	/* _SDSPARSER_H */

